/**
 * Definition of peel node entity.
 *
 * \file graph.hpp
 * \author tomby
 * \date 04-01-2009
 **/

/*  Copyright (C) 2009  Tomas 'tomby' Bily

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */


#ifndef __DBC_GRAPH__
#define __DBC_GRAPH__

namespace dbc {
  namespace peel {

    using namespace dbc::temporal;

    class Graph : public Node
    {
      ENTITY_DEF (Graph);

    public:
      typedef std::vector<Node::Ptr> NodeContainerType;
      typedef std::vector<Edge::Ptr> EdgeContainerType;
      typedef boost::shared_ptr<NodeContainerType> NodeContainerPtrType;
      typedef boost::shared_ptr<EdgeContainerType> EdgeContainerPtrType;
      typedef NodeContainerType::iterator NodeIterator;
      typedef EdgeContainerType::iterator EdgeIterator;

    protected:
      NodeContainerPtrType nodes;
      EdgeContainerPtrType edges;

    public:
      Graph ()
      { ENTITY_CTOR_IMPL (Graph); }

      void compute_sink_levels ();
      
      inline void add_node (Node* node)
      { nodes->push_back (node); }

      inline void add_edge (Edge* edge)
      { edges->push_back (edge); }

      inline NodeIterator begin_nodes ()
      { return nodes->begin (); }

      inline NodeIterator end_nodes ()
      { return nodes->end (); }

      inline EdgeIterator begin_edges ()
      { return edges->begin (); }

      inline EdgeIterator end_edges ()
      { return edges->end (); }

      static inline void connect (Node* node1, Node* node2, Edge* e)
      {
	node1->add_out_edge (e);
	node2->add_in_edge (e);
	e->add_in_node (node1);
	e->add_out_node (node2);
      }

      inline void connect (int n1, int n2, Edge* e)
      { connect ((*nodes) [n1].get (), (*nodes) [n2].get (), e); }

      inline void connect (int n1, int n2, int e)
      { connect ((*nodes) [n1].get (), (*nodes) [n2].get (), (*edges) [e].get ()); }
    };

    class SimGraph : public Graph
    {
      ENTITY_DEF (SimGraph);

    public:
      typedef Scheduler<StampableEntity::Ptr, StampableEntity::Cmp> SchedulerType;

    protected:
      SchedulerType* scheduler;
      double t;

    public:
      SimGraph ()
	: scheduler (NULL), t (0)
      { ENTITY_CTOR_IMPL (SimGraph); }

      virtual ~SimGraph ();

      void start ();
      void step ();
      void update_by_scheduler ();

      virtual void update_state ();
    };

  };
};

#endif
